package com.imis.module.api.bus;

import com.imis.base.annotation.VerificationCaptcha;
import com.imis.base.constant.CacheConstant;
import com.imis.base.constant.CommonConstant;
import com.imis.base.constant.enums.ArgumentResponseEnum;
import com.imis.base.constant.enums.VerificationCodeTypeEnum;
import com.imis.base.globle.response.BaseResponse;
import com.imis.base.globle.response.CommonResponse;
import com.imis.base.shiro.UserInfo;
import com.imis.base.shiro.util.JwtUtil;
import com.imis.base.util.CurrentUserUtils;
import com.imis.base.util.PasswordUtil;
import com.imis.module.api.model.ro.LoginDTO;
import com.imis.module.api.model.ro.PhoneLoginDTO;
import com.imis.module.api.model.ro.UserChangePasswordDTO;
import com.imis.module.api.model.ro.UserRegisterDTO;
import com.imis.module.base.BaseBus;
import com.imis.module.system.model.converter.SysUserConverter;
import com.imis.module.system.model.po.SysUser;
import com.imis.module.system.model.vo.SysMenuTreeVO;
import com.imis.module.system.model.vo.SysRoleVO;
import com.imis.module.system.model.vo.SysUserOrganizationVO;
import com.imis.module.system.model.vo.SysUserVO;
import com.imis.module.system.service.ISysMenuService;
import com.imis.module.system.service.ISysOrganizationService;
import com.imis.module.system.service.ISysRoleService;
import com.imis.module.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * SysLoginBus<br>
 * 登录相关功能 业务处理类
 * </p>
 *
 * @author XinLau
 * @version 1.0
 * @since 2020年03月10日 09:18
 */
@Service
public class LoginBus extends BaseBus {

    /**
     * 系统用户表 服务类
     */
    private ISysUserService sysUserService;

    @Autowired
    public void setSysUserService(ISysUserService sysUserService) {
        this.sysUserService = sysUserService;
    }

    /**
     * 系统角色表-菜单权限组 服务类
     */
    private ISysRoleService serviceBySysRoleService;

    @Autowired
    public void setServiceBySysRoleService(ISysRoleService serviceBySysRoleService) {
        this.serviceBySysRoleService = serviceBySysRoleService;
    }

    /**
     * 功能菜单表 服务类
     */
    private ISysMenuService serviceBySysMenuService;

    @Autowired
    public void setServiceBySysMenuService(ISysMenuService serviceBySysMenuService) {
        this.serviceBySysMenuService = serviceBySysMenuService;
    }

    /**
     * 组织机构 服务类
     */
    private ISysOrganizationService serviceBySysOrganizationService;

    @Autowired
    public void setSysOrganizationService(ISysOrganizationService serviceBySysOrganizationService) {
        this.serviceBySysOrganizationService = serviceBySysOrganizationService;
    }

    /**
     * 注册校验用户
     *
     * @param register - 用户注册对象
     * @return SysUser - 用户
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/9 9:47
     */
    private SysUser registrationVerification(final UserRegisterDTO register) {
        List<SysUser> sysUserList = this.sysUserService.duplicateRegistrationVerification(register);
        for (SysUser sysUser : sysUserList) {
            // 情况1：根据用户信息查询，该用户已注销
            ArgumentResponseEnum.USER_REGISTER_ERR_DELETE.assertIsFalse(CommonConstant.DEL_FLAG_NOT_DELETE.equals(sysUser.getDelFlag()), sysUser.getUsername());
            // 情况2：根据用户信息查询，该用户已冻结
            ArgumentResponseEnum.USER_REGISTER_ERR_FREEZE.assertIsFalse(CommonConstant.USER_UNFREEZE.equals(sysUser.getStatus()), sysUser.getUsername());
            // 情况3：根据用户信息查询，该用户存在
            ArgumentResponseEnum.USER_REGISTER_ERR_REPEAT.assertIsNull(sysUser, sysUser.getUsername());
        }
        return SysUserConverter.INSTANCE.getAddEntity(register);
    }

    /**
     * 账号登录校验用户是否有效
     *
     * @param sysUser - 系统用户
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/9 9:47
     */
    private void checkUserIsEffective(SysUser sysUser) {
        // 情况1：根据用户信息查询，该用户不存在
        ArgumentResponseEnum.USER_LOGIN_ERR_NON.assertNotNull(sysUser, sysUser.getUsername());
        // 情况2：根据用户信息查询，该用户已注销
        ArgumentResponseEnum.USER_LOGIN_ERR_DELETE.assertIsFalse(CommonConstant.DEL_FLAG_NOT_DELETE.equals(sysUser.getDelFlag()), sysUser.getUsername());
        // 情况3：根据用户信息查询，该用户已冻结
        ArgumentResponseEnum.USER_LOGIN_ERR_FREEZE.assertIsFalse(CommonConstant.USER_UNFREEZE.equals(sysUser.getStatus()), sysUser.getUsername());
    }

    /**
     * 手机号登录校验用户是否有效
     *
     * @param sysUser - 系统用户
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/9 9:47
     */
    private void checkPhoneIsEffective(SysUser sysUser) {
        // 情况1：根据用户信息查询，该用户不存在
        ArgumentResponseEnum.USER_LOGIN_ERR_NON.assertNotNull(sysUser, sysUser.getPhone());
        // 情况2：根据用户信息查询，该用户已注销
        ArgumentResponseEnum.USER_LOGIN_ERR_DELETE.assertIsFalse(CommonConstant.DEL_FLAG_NOT_DELETE.equals(sysUser.getDelFlag()), sysUser.getPhone());
        // 情况3：根据用户信息查询，该用户已冻结
        ArgumentResponseEnum.USER_LOGIN_ERR_FREEZE.assertIsFalse(CommonConstant.USER_UNFREEZE.equals(sysUser.getStatus()), sysUser.getPhone());
    }

    /**
     * 用户注册
     *
     * @param register - 用户注册对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/5 17:25
     */
    @VerificationCaptcha(type = VerificationCodeTypeEnum.SMS, captcha = "#register.captcha", verificationCodeIdentification = "#register.verificationCodeIdentification")
    public CommonResponse<SysUserVO> register(final UserRegisterDTO register) {
        // 1、校验用户重复
        SysUser sysUser = this.registrationVerification(register);
        // 2、创建新用户
        sysUser.setCreateBy(0L);
        boolean saveUser = this.sysUserService.saveUser(sysUser);
        // 判断保存成功
        ArgumentResponseEnum.USER_REGISTER_ERR.assertIsTrue(saveUser);
        return new CommonResponse(SysUserConverter.INSTANCE.getReturnValue(sysUser));
    }

    /**
     * 用户相关信息
     *
     * @param sysUser 系统用户
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/10 10:30
     */
    private CommonResponse<UserInfo> userInfo(SysUser sysUser) {
        /*
         * Tip：修改此处Token需要连带修改
         * com.imis.base.shiro.authc.ShiroRealm#jwtTokenRefresh(java.lang.String, java.lang.String, java.lang.String)
         * com.imis.module.system.bus.SysUserBus#freezeUserByIdentification(java.lang.String)
         */
        String sysPassword = sysUser.getPassword();
        String username = sysUser.getUsername();
        // 生成Token
        String token = JwtUtil.sign(username, sysPassword);
        // 生成Key
        String key = JwtUtil.getTokenKey(username, sysPassword);
        // 1.存放用户Token     设置超时时间
        this.redisUtil.set(key, token, JwtUtil.EXPIRE_TIME);
        // 用户信息返回值
        SysUserVO sysUserVO = SysUserConverter.INSTANCE.getReturnValue(sysUser);
        // 角色信息返回值
        List<SysRoleVO> roleList = this.serviceBySysRoleService.selectSysRoleListByUserId(sysUser.getId());
        // 组织机构信息
        List<SysUserOrganizationVO> organizationList = serviceBySysOrganizationService.queryOrganizationByUserIdentification(sysUser.getId());
        // 构建数据
        UserInfo userInfo = new UserInfo(token, sysUserVO, roleList, organizationList);
        // 2.存放用户编号与Token的Key
        Map<String, Object> userTokenMap = new HashMap<>(1);
        userTokenMap.put(sysUser.getId().toString(), key);
        this.redisUtil.hmset(CacheConstant.PREFIX_SYS_USER_ID_TOKEN, userTokenMap);
        return new CommonResponse(userInfo);
    }

    /**
     * 用户登录
     *
     * @param login - 用户登录表单对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/6 14:26
     */
    @VerificationCaptcha(verification = false, type = VerificationCodeTypeEnum.OPERATION, captcha = "#login.captcha", verificationCodeIdentification = "#login.verificationCodeIdentification")
    public CommonResponse<UserInfo> login(final LoginDTO login) {
        // 用户名
        String username = login.getUsername();
        SysUser sysUser = this.sysUserService.queryUserByName(username);
        // 1.账号登录校验用户是否有效
        this.checkUserIsEffective(sysUser);
        // 2. 校验用户名或密码是否正确
        String userPassword = PasswordUtil.encrypt(username, login.getPassword(), sysUser.getSalt());
        ArgumentResponseEnum.USER_LOGIN_ERR.assertIsTrue(userPassword.equals(sysUser.getPassword()), username);
        // 3.用户登录信息
        return userInfo(sysUser);
    }

    /**
     * 用户登录
     *
     * @param phoneLogin - 手机登录表单对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/6 14:26
     */
    @VerificationCaptcha(type = VerificationCodeTypeEnum.SMS, captcha = "#phoneLogin.captcha", verificationCodeIdentification = "#phoneLogin.phone")
    public CommonResponse<UserInfo> loginByPhone(final PhoneLoginDTO phoneLogin) {
        // 1.校验用户是否有效
        String loginPhone = phoneLogin.getPhone();
        SysUser sysUser = this.sysUserService.queryUserByPhone(loginPhone);
        this.checkPhoneIsEffective(sysUser);
        // 2.用户登录信息
        return userInfo(sysUser);
    }

    /**
     * 用户自助修改密码
     *
     * @param changePassword - 自助密码修改对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/23 12:31
     */
    @VerificationCaptcha(type = VerificationCodeTypeEnum.SMS, captcha = "#changePassword.captcha", verificationCodeIdentification = "#changePassword.verificationCodeIdentification")
    public BaseResponse passwordChange(final UserChangePasswordDTO changePassword) {
        // 1.密码重复性判断
        String username = changePassword.getUsername();
        // 2.用户合法性判断
        SysUser sysUser = this.sysUserService.queryUserByName(username);
        ArgumentResponseEnum.CHANGE_USER_PASSWORD_ERR_NON_USER.assertNotNull(sysUser, username);
        // 3.修改密码 （这里不考虑清缓存：业务场景：用户重置密码，用户不在线）
        boolean change = this.sysUserService.changeUserPassword(sysUser.getUsername(), changePassword.getNewPassword());
        ArgumentResponseEnum.USER_REGISTER_ERR.assertIsTrue(change, username);
        return new BaseResponse();
    }

    /**
     * 查询当前用户的功能菜单树
     *
     * @return List
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/23 12:31
     */
    public CommonResponse<List<SysMenuTreeVO>> querySysMenuTreeListByCurrentUser() {
        // 1.获取用户角色
        Long roleId = CurrentUserUtils.getRoleIdFormHttpServletRequest();
        ArgumentResponseEnum.MENU_TREE_QUERY_ERR_NON_ROLE.assertNotNull(roleId, CurrentUserUtils.getUserNameByToken());
        // 2.获取所有角色的功能菜单树
        List<SysMenuTreeVO> sysMenuTreeListByRoleId = this.serviceBySysMenuService.querySysMenuTreeListByRoleId(roleId);
        return new CommonResponse(sysMenuTreeListByRoleId);
    }

}
